//
// Created by 王筱童 on 2022/5/9.
//

#include "redis_server.h"
#include <iostream>
#include "others.h"
#include <experimental/source_location>

asio::awaitable<void> redis_server::listen() {
    try {
        auto executor=co_await asio::this_coro::executor;
        for(;;){
#ifdef TEST
            std::cout<<"Wait connection....\n";
#endif
            auto socket=co_await acceptor.async_accept(executor,asio::use_awaitable);
#ifdef TEST
            std::cout<<"Enstablish connection from: "+socket.remote_endpoint().address().to_string()+":"+std::to_string(ntohs(socket.remote_endpoint().port()))+"\n";
#endif
            conn_ptr conn=std::make_unique<redis_connection>(std::move(socket),this,conn_index);
            auto ptr=conn.get();
            connections[conn_index++]=std::move(conn);
            asio::co_spawn(run_context,ptr->start(),asio::detached);
        }
    }catch (const std::exception&ec){
        std::cerr<<"error: "<<std::experimental::source_location::current().function_name() <<" "<<ec.what()<<std::endl;
    }
    co_return ;
}
asio::awaitable<void> redis_server::init(){
    co_await save.reload();
    co_return ;
}
void redis_server::register_timer() {
}

void redis_server::run() {
    register_timer();
    asio::co_spawn(io_context,listen(),asio::detached);
    asio::co_spawn(run_context,init(),asio::detached);
    io_context.run();
}

void redis_server::close_conn(std::size_t index) {
    connections.erase(index);
}

redis_server::redis_server(const std::string& ip, std::uint16_t port):
io_worker(io_context),
run_worker(run_context),
run_thread([this](){
    run_context.run();
}),
timer_worker(timer_context),
timer_thread([this](){
    timer_context.run();
}),
acceptor(io_context,{asio::ip::make_address(ip),port}),
cmd_run(this),
save(this),
senti(this),
slaves(this)
{
}

std::string redis_server::exec_command(const std::string& command, const std::vector<std::string>& args, std::size_t index) {
#ifdef TEST
    std::cout<<std::experimental::source_location::current().function_name()<<std::endl;
    std::cout<<"argument command:"+command+"\n";
#endif
    return join(cmd_run.exec_command(command,args,index),'\n')+"\n";
}
